package atguigu.scada;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
import org.eclipse.milo.opcua.stack.client.DiscoveryClient;
import org.eclipse.milo.opcua.stack.core.Stack;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.*;
import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.ExecutionException;

import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;

@Slf4j
public class OpcuaHelper {

//	public  static final String URL = "opc.tcp://10.18.62.24:50000";
	public  static final String URL = "opc.tcp://10.16.152.135:18312/";


	public static EndpointDescription endpoint = null;

	private EndpointDescription getEndpoint() throws Exception {
		log.debug("endpoint >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+endpoint);
		if(endpoint==null){
			List<EndpointDescription> endpoints;
			try {
				endpoints = DiscoveryClient.getEndpoints(URL).get();
			} catch (Throwable ex) {
				String discoveryUrl = URL;

				if (!discoveryUrl.endsWith("/")) {
					discoveryUrl += "/";
				}
				discoveryUrl += "discovery";

				log.info("Trying explicit discovery URL: {}", discoveryUrl);
				endpoints = DiscoveryClient.getEndpoints(discoveryUrl).get();
			}
			endpoint = endpoints.stream()
					.filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())).filter(e -> true).findFirst()
					.orElseThrow(() -> new Exception("no desired endpoints returned"));
		}
		return endpoint;
	}

	private OpcUaClient createClient() throws Exception {
		Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
		Files.createDirectories(securityTempDir);
		if (!Files.exists(securityTempDir)) {
			throw new Exception("unable to create security dir: " + securityTempDir);
		}
		LoggerFactory.getLogger(getClass()).info("security temp dir: {}", securityTempDir.toAbsolutePath());
		KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir);

		SecurityPolicy securityPolicy = SecurityPolicy.None;
		EndpointDescription endpoint = getEndpoint();
		log.info("Using endpoint: {} [{}/{}]", endpoint.getEndpointUrl(), securityPolicy,
				endpoint.getSecurityMode());
		OpcUaClientConfig config = OpcUaClientConfig.builder()
				.setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
				.setApplicationUri("urn:eclipse:milo:examples:client")
				.setCertificate(loader.getClientCertificate())
				.setKeyPair(loader.getClientKeyPair()).setEndpoint(endpoint)
				.setIdentityProvider(new AnonymousProvider())
				.setRequestTimeout(uint(5000))
				.setSessionTimeout(uint(5000))
				.setConnectTimeout(uint(5000))
				.build();
		return OpcUaClient.create(config);
	}

	public StatusCode writeBool(OpcUaClient client, Integer ns, String node, Boolean bool)
			throws ExecutionException, InterruptedException {
		NodeId nodeId = new NodeId(ns, node);
		Variant v = new Variant(bool);
		DataValue dataValue = new DataValue(v, null, null);
		StatusCode statusCode = client.writeValue(nodeId, dataValue).get();
		return statusCode;
	}


	public boolean t(String acode,String nodeId){
		return sendBoolSignal(1,acode+"/"+nodeId,true);
	}

	public boolean f(String acode,String nodeId){
		return sendBoolSignal(1,acode+"/"+nodeId,false);
	}

	public boolean n(String acode,String nodeId,int num){
		return sendNumSignal(1,acode+"/"+nodeId,num);
	}

	public boolean sendBoolSignal(int namespaceIndex, String identifier,boolean flag){
		boolean b = false;
		try{
			OpcUaClient client = createClient();
			client.connect().get();
			StatusCode statusCode = writeBool(client,namespaceIndex,identifier,flag);
			if(statusCode.isGood()) {
				client.disconnect().get();
				Stack.releaseSharedResources();
				b = true;
			}
		}catch (Exception e){
			log.error("发送信号失败",e);
		}
		return b;
	}

	// 发送连续间隔信号
	public boolean sendNumSignal(int namespaceIndex, String identifier,int num) {
		boolean b = false;
		try{
			OpcUaClient client = createClient();
			client.connect().get();
			NodeId node = new NodeId(namespaceIndex,identifier);
			Variant v = new Variant(num);
			DataValue dataValue = new DataValue(v,null,null);
			StatusCode statusCode = client.writeValue(node,dataValue).get();
			if (statusCode.isGood()) {
				client.disconnect().get();
				Stack.releaseSharedResources();
				b = true;
			}
		}catch (Exception e){
			log.error("发送信号失败",e);
		}
		return b;
	}
}
